package br.pucrio.inf.csm.caching;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * Implements a Less Frequently Used cache. For each retrieve call on the 
 * element the number of hits is updated. When a store call is made for a new
 * element (and assuming the max limit is reached) the element with least
 * number of hits, the Less Frequently Used element, is evicted.
 * 
 * Obs.: Not thread safe!!
 * 
 * @author agazola
 *
 */
public class LFUCachePolicy implements ICachePolicy {

	private Map values;

	private Map<Object, Integer> frequencyMap;

	private int maxSize;

	public LFUCachePolicy(int maxSize) {
		frequencyMap = new HashMap<Object, Integer>(maxSize);
		this.maxSize = maxSize;
	}

	@Override
	public Object retrieve(Object key) {
		return values.get(key);
	}

	@Override
	public void store(Object key, Object value) {
		if (values.size() == maxSize) {
			evict();
		}
		values.put(key, value);
		updateFrequency(key);
	}
	
	@Override
	public void setValues(Map values) {
		this.values = values;
	}

	private void updateFrequency(Object key) {
		Integer frequency = frequencyMap.get(key);
		if (frequency == null) {
			frequencyMap.put(key, 1);
		} else {
			frequencyMap.put(key, ++frequency);
		}
	}

	private void evict() {
		frequencyMap.values().remove(Collections.min(frequencyMap.values()));
	}
}
